【分布式日志系统】springboot+zipkin+dubbo实现链路跟踪(下) 您所在的位置:网站首页 springboot Zipkin 【分布式日志系统】springboot+zipkin+dubbo实现链路跟踪(下)

【分布式日志系统】springboot+zipkin+dubbo实现链路跟踪(下)

2024-04-10 20:40| 来源: 网络整理| 查看: 265

上一篇写了《【分布式日志系统】springboot+zipkin+dubbo实现链路跟踪(上)》《【分布式日志系统】springboot+zipkin+dubbo实现链路跟踪(中)》,有兴趣的小伙伴可以往回翻翻,这一篇解决如何跟踪。

一、基本操作pom添加依赖(常规操作);定义公共跟踪配置类dubbo服务端和调用端集成相应配置(主要是yaml中配置);验证。二、环境介绍

提示:可能不同的框架版本会导致有些地方不生效(如sleuth不支持apache版的dubbo),大家在集成的过程中有问题可以私信我,共同探讨。主框架版本如下:springboot 2.6.6、 dubbo 2.7.12、 zipkin 2.16.3、 brave 5.13.3 nacos-discovery-spring-boot-starter 0.2.10、 nacos-config-spring-boot-starter 0.2.10、

三 工程结构basic-platform:父工程,管理框架版本等基础依赖;basic-common:基础工具包,“定义公共跟踪基础配置类”等均在此工程,其他工程均依赖该工程;basic-portal:门户的父工程(pom工程),其下包含三个子工程:server:前后端分离对应的后端服务 ;portal-api:定义dubbo服务的接口;portal-api-impl:定义portal-api对应的接口实现;basic-foundation:基础的父工程(pom工程),其下包含两个子工程:foundation-api:定义dubbo服务的接口;foundation-api-impl:定义 foundation-api对应的接口实现;四、pom依赖

主要的代码均在basic-common的pom中,添加如下依赖:

org.apache.dubbo dubbo provided io.zipkin.brave brave-instrumentation-dubbo io.zipkin.brave brave-spring-beans io.zipkin.brave brave-context-slf4j io.zipkin.reporter2 zipkin-sender-okhttp3 io.zipkin.brave brave-instrumentation-spring-webmvc io.zipkin.brave brave-instrumentation-httpclient io.zipkin.reporter2 zipkin-sender-okhttp3

另外,需要定义一个配置类,来处理RPC的tracing,要不会不生效。

package com.wd.basic.common.support.trace; import brave.CurrentSpanCustomizer; import brave.SpanCustomizer; import brave.Tracing; import brave.context.slf4j.MDCScopeDecorator; import brave.http.HttpTracing; import brave.propagation.B3Propagation; import brave.propagation.ExtraFieldPropagation; import brave.propagation.ThreadLocalCurrentTraceContext; import brave.rpc.RpcTracing; import brave.sampler.Sampler; import brave.servlet.TracingFilter; import brave.spring.webmvc.SpanCustomizingAsyncHandlerInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import zipkin2.Span; import zipkin2.codec.Encoding; import zipkin2.reporter.AsyncReporter; import zipkin2.reporter.Sender; import zipkin2.reporter.okhttp3.OkHttpSender; import javax.servlet.Filter; @Configuration @Import(SpanCustomizingAsyncHandlerInterceptor.class) public class TracingConfig implements WebMvcConfigurer { @Bean Sender sender(@Value("${zipkin.base.url}") String url) { return OkHttpSender.newBuilder() .encoding(Encoding.PROTO3) .endpoint(url) .build(); } /** * Configuration for how to buffer spans into messages for Zipkin */ @Bean @ConditionalOnBean(Sender.class) AsyncReporter spanReporter(Sender sender) { AsyncReporter.Builder builder = AsyncReporter.builder(sender); builder.queuedMaxSpans(50000); builder.queuedMaxBytes(104857600); return builder.build(); } /** * Controls aspects of tracing such as the service name that shows up in the UI */ @Bean Tracing tracing(@Value("${dubbo.application.name}") String applicationName, @Value("${zipkin.enable:false}") Boolean enable, @Autowired(required = false) AsyncReporter spanReporter) { Tracing.Builder builder = Tracing.newBuilder() .localServiceName(applicationName) .propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "user-name")) .currentTraceContext(ThreadLocalCurrentTraceContext.newBuilder() // puts trace IDs into logs .addScopeDecorator(MDCScopeDecorator.create()) .build() ); if (enable) { builder.spanReporter(spanReporter); builder.sampler(Sampler.ALWAYS_SAMPLE); } else { builder.sampler(Sampler.NEVER_SAMPLE); } return builder.build(); } @Bean SpanCustomizer spanCustomizer(Tracing tracing) { return CurrentSpanCustomizer.create(tracing); } /** * Decides how to name and tag spans. By default they are named the same as the http method */ @Bean HttpTracing httpTracing(Tracing tracing) { return HttpTracing.create(tracing); } @Bean RpcTracing rpcTracing(Tracing tracing) { return RpcTracing.create(tracing); } /** * Creates server spans for http requests */ @Bean Filter tracingFilter(HttpTracing httpTracing) { return TracingFilter.create(httpTracing); } @Autowired SpanCustomizingAsyncHandlerInterceptor webMvcTracingCustomizer; /** * Decorates server spans with application-defined web tags */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(webMvcTracingCustomizer); } } 五、其他工程添加配置

前提:所有工程均依赖basic-common。 dubbo工程的provider和consumer均添加如下配置(请注意必须添加dubbo.consumer.filter和dubbo.provider.filter)

dubbo: application: name: foundationRpc #服务名称 consumer: timeout: 3000 #消费超时时间 retries: 1 #重试次数 filter: tracing # 请注意必须添加该配置 check: false provider: filter: tracing # 请注意必须添加该配置 protocol: name: dubbo zipkin: enable: true base: url: http://127.0.0.1:9411/api/v2/spans 六、测试

设计如下调用关系:

server定义http入口:

@GetMapping("tracing") public String exec(){ log.info("come in tracing"); return rpcDemoService.tracing(); }

rpcDemoService为server中定义的service,实现如下:

package com.wd.basic.portal.server.modular.demo.service.impl; import cn.hutool.core.util.StrUtil; import com.wd.basic.foundation.rpc.test.service.DemoRpcService; import com.wd.basic.portal.rpc.IDemoService; import com.wd.basic.portal.rpc.ITraceDemoService; import com.wd.basic.portal.server.modular.demo.service.RpcDemoService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.stereotype.Service; /** * rpc演示服务impl * * @author 小尘哥 * @date 2022/04/14 */ @Slf4j @Service public class RpcDemoServiceImpl implements RpcDemoService { @DubboReference(interfaceClass = IDemoService.class, version = "2.0") private IDemoService demoService2; @DubboReference(interfaceClass = IDemoService.class, version = "1.0") private IDemoService demoService1; @DubboReference(interfaceClass = ITraceDemoService.class, version = "1.0") private ITraceDemoService traceDemoService; @DubboReference(interfaceClass = DemoRpcService.class, version = "1.0") private DemoRpcService demoRpcService; @Override public String tracing() { log.info("come in exec service"); String rpc2 = demoService2.testRpc(); return StrUtil.join(",", rpc2); } }

IDemoService 定义在portal-api中,实现如下

package com.wd.basic.portal.rpc.impl; import com.wd.basic.foundation.rpc.test.service.DemoRpcService; import com.wd.basic.portal.rpc.IDemoService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.apache.dubbo.config.annotation.DubboService; /** * 演示服务impl * * @author 小尘哥 * @date 2022/03/16 */ @Slf4j @DubboService(interfaceClass = IDemoService.class,version = "2.0") public class DemoServiceV2Impl implements IDemoService { @DubboReference(interfaceClass = DemoRpcService.class, version = "1.0") private DemoRpcService demoRpcService; @Override public String testRpc() { log.info("来自统一门户 RPC 测试"); demoRpcService.testRpc(); return "调用到了rpc服务 version 2.0.0"; } }

DemoRpcService 定义在foundation-api中,实现如下:

package com.wd.basic.foundation.rpc.test.service.impl; import com.wd.basic.foundation.rpc.test.service.DemoRpcService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboService; /** * test Rpc服务 * @author 上官婉儿 */ @Slf4j @DubboService(interfaceClass = DemoRpcService.class,version = "1.0") public class DemoRpcServiceImpl implements DemoRpcService { @Override public String testRpc() { log.info("来自基础服务 RPC 测试"); return "RPC服务! from foundation"; } }

七、日志配置

临门一脚了,以上都配置好了,但是哪里能看到效果呢?肯定是需要从日志来跟踪,我们采用springboot推荐的logback来记录日志,请注意日志记录格式,添加了部分内容“【%X{traceId},%X{spanId},%X{parentId}】”,完整配置如下:

Logback For Basic Platform %d{yyyy-MM-dd HH:mm:ss.SSS} 【%X{traceId},%X{spanId},%X{parentId}】 [%thread] %-5level %logger-%msg%n %ex{5} UTF-8 ${logDir}/%d{yyyy-MM-dd}/pf.%i.log.zip 50MB ${logMaxHistory} 10GB %d{yyyy-MM-dd HH:mm:ss.SSS} 【%X{traceId},%X{spanId},%X{parentId}】 [%thread] %-5level %logger-%msg%n %ex{5} true 0 512 八、验证

来自server的日志

2022-04-26 16:44:25.817 【2926aa52265ad112,2926aa52265ad112,】 [http-nio-8080-exec-1] INFO com.wd.basic.portal.server.modular.demo.controller.RpcDemoController-come in tracing 2022-04-26 16:44:25.826 【2926aa52265ad112,2926aa52265ad112,】 [http-nio-8080-exec-1] INFO com.wd.basic.portal.server.modular.demo.service.impl.RpcDemoServiceImpl-come in exec service

来自portal-api的日志

2022-04-26 16:44:25.882 【2926aa52265ad112,6a4da6311934ab65,2926aa52265ad112】 [DubboServerHandler-10.1.252.224:20881-thread-5] INFO com.wd.basic.portal.rpc.impl.DemoServiceV2Impl-来自统一门户 RPC 测试

来自foundation-api的日志

2022-04-26 16:44:25.926 【2926aa52265ad112,53dbfb344223ef50,6a4da6311934ab65】 [DubboServerHandler-10.1.252.224:20880-thread-3] INFO com.wd.basic.foundation.rpc.test.service.impl.DemoRpcServiceImpl-来自基础服务 RPC 测试九、日志分析

提取三部分日志中括号中的内容:

统一门户:traceId = 2926aa52265ad112,spanId=2926aa52265ad112,parentId=’’; 统一门户RPC服务:traceId = 2926aa52265ad112,spanId=6a4da6311934ab65,parentId=2926aa52265ad112; 基础服务RPC服务:traceId = 2926aa52265ad112,spanId=53dbfb344223ef50,parentId=6a4da6311934ab65;

说明:

对于server,作为请求入口,因此traceId和spanId相同,无上游服务,因此parentId为空。对于portal-api服务,parentId=统一门户请求入口的spanId,因此它是统一门户的下游服务。对于foundation-api服务,parentId=同一门户RPC服务的spanId,因此它是统一门户RPC服务的下游服务。

综上,和测试开始时的设计逻辑一致,由traceId串联整个请求过程,由spanId和parentId构建上下游调用关系,完成dubbo服务之间调用的链路跟踪。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有